package com.heima.wemedia.service.impl;

import com.alibaba.fastjson.JSON;
import com.heima.apis.schedule.IScheduleClient;
import com.heima.model.common.dtos.ResponseResult;
import com.heima.model.common.enums.TaskTypeEnum;
import com.heima.model.schedule.dtos.Task;
import com.heima.model.wemedia.pojos.WmNews;
import com.heima.utils.common.ProtostuffUtil;
import com.heima.wemedia.service.WmNewsAutoScanService;
import com.heima.wemedia.service.WmNewsTaskService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;

import java.util.Date;

@Service
@Slf4j
public class WmNewsTaskServiceImpl implements WmNewsTaskService {

    @Autowired
    private IScheduleClient scheduleClient;
    /**
     * 添加任务到延迟队列
     * @param id          文章id
     * @param publishTime 文章发布时间(任务的执行时间)
     */
    @Override
    @Async //因为发布文章的时候需要异步调用
    public void addNewsToTask(Integer id, Date publishTime) {

        log.info("添加文章定时审核任务到延迟服务中----begin");

        //调用远程接口添加任务
        log.info("添加任务到延迟队列中，文章id:{},发布(执行)时间:{}", id, publishTime);
        Task task = new Task();
        task.setExecuteTime(publishTime.getTime());
        //后续拉取任务是需要用到这两个属性

        //文章定时审核对应的具体业务类型
        task.setTaskType(TaskTypeEnum.NEWS_SCAN_TIME.getTaskType());
        //文章定时审核对应的业务不同优先级别
        task.setPriority(TaskTypeEnum.NEWS_SCAN_TIME.getPriority());

        WmNews wmNews = new WmNews();
        wmNews.setId(id);
        //封装文章id，后面拉取到任务之后，审核时，需要传文章id给autoScanWmNews()

        //Parameters属性是byte[]类型，所以要把参数wmNews进行序列化(将对象转化为可存储或传输的格式的过程。
        // 这个过程使得我们能够将复杂的数据结构（如对象、数组等）转换为一种简单的字节流或文本格式（如JSON、XML等）。
        // 序列化之后，数据可以被保存到文件中、通过网络传输或存储在数据库中。)

        //需要传文章id，(需要审核的是这个文章)
        //TODO 但是Parameters要传的是对象？？，把ID封装进对象中，再传过去，为什么？？？
        task.setParameters(ProtostuffUtil.serialize(wmNews));

        scheduleClient.addTask(task);
        log.info("添加文章定时审核任务到延迟服务中----end");
    }

    @Autowired
    private WmNewsAutoScanService wmNewsAutoScanService;

    /**
     * 从延迟队列中获取任务，进行审核（消费任务）
     */
    @Override
    @Scheduled(fixedRate = 1000)//需要在启动类中开启定时任务，否则不生效
    //不被其它方法调用，但是也要执行，按照固定的频率拉取任务，每秒钟拉取一次
    public void scanNewsByTask() {
        log.info("从延迟服务中拉取任务，消费任务：审核文章----begin");

        ResponseResult responseResult = scheduleClient.poll
                (TaskTypeEnum.NEWS_SCAN_TIME.getTaskType(), TaskTypeEnum.NEWS_SCAN_TIME.getPriority());

        if(responseResult.getCode().equals(200) && responseResult.getData() != null) {
            // 状态码为200且返回的responseResult里的任务不为空

//            JSON.toJSONString(responseResult.getData()); //Data是T类型，需要转成Json类型
            // 再把responseResult转换成的Json类型转成Task类型 (T类型转json，json再转Task类型)
            Task task = JSON.parseObject(JSON.toJSONString(responseResult.getData()), Task.class);
            log.info("从延迟队列中获取到任务:{}", task);
            //反序列化，因为在addNewsToTask里task.setParameters(ProtostuffUtil.serialize(wmNews));
            //是把wmNews序列化后再传给Parameters的，所以这里要反序列化，拿到wmNews对象之后，再.getId()
            WmNews wmNews = ProtostuffUtil.deserialize(task.getParameters(), WmNews.class);
            // 调用远程接口，进行审核
            wmNewsAutoScanService.autoScanWmNews(wmNews.getId());
            log.info("从延迟服务中拉取任务，消费任务：审核文章----end");
        } else {
            log.info("延迟服务中没有审核文章的任务，拉取失败---end");
        }
    }
}
